/**
 * There are <a href="https://github.com/thinkgem/jeesite">JeeSite</a> code generation
 */
package com.thinkgem.jeesite.modules.bls.service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.thinkgem.jeesite.common.persistence.Page;
import com.thinkgem.jeesite.common.service.BaseService;
import com.thinkgem.jeesite.modules.bls.dao.LoanDao;
import com.thinkgem.jeesite.modules.bls.entity.Loan;
import com.thinkgem.jeesite.modules.sys.utils.workflow.ProcessDefinitionKey;

/**
 * 信贷分析Service
 * 
 * @author edpdennis
 * @version 2013-04-19
 */
@Component
@Transactional(readOnly = true)
public class LoanService extends BaseService {

	@SuppressWarnings("unused")
	private static Logger logger = LoggerFactory.getLogger(LoanService.class);

	@Autowired
	private LoanDao loanDao;
	@Autowired
	private RuntimeService runtimeService;
	@Autowired
	protected TaskService taskService;
	@Autowired
	protected HistoryService historyService;
	@Autowired
	protected RepositoryService repositoryService;
	@Autowired
	private IdentityService identityService;

	public Loan get(Long id) {
		return loanDao.findOne(id);
	}

	public Page<Loan> find(Page<Loan> page, Loan loan) {
		DetachedCriteria dc = loanDao.createDetachedCriteria();
		dc.createAlias("office", "office");
		if (loan.getOffice() != null && loan.getOffice().getId() != null) {
			dc.add(Restrictions.or(Restrictions.eq("office.id", loan
					.getOffice().getId()), Restrictions.eq("office.parent.id",
					loan.getOffice().getId()), Restrictions.like(
					"office.parentIds", "%," + loan.getOffice().getId() + ",%")));
		}
		if (StringUtils.isNotEmpty(loan.getType())) {
			dc.add(Restrictions.eq("type", loan.getType()));
		}
		if (null != loan.getStartdate()) {
			dc.add(Restrictions.eq("startdate", loan.getStartdate()));
		}
		if (null != loan.getEnddate()) {
			dc.add(Restrictions.eq("enddate", loan.getEnddate()));
		}
		if (StringUtils.isNotEmpty(loan.getIscheck())) {
			dc.add(Restrictions.eq("ischeck", loan.getIscheck()));
		}
		if (StringUtils.isNotEmpty(loan.getOfficerid())) {
			dc.add(Restrictions.like("officerid", "%" + loan.getOfficerid()
					+ "%"));
		}

		dc.addOrder(Order.desc("id"));
		return loanDao.find(page, dc);
	}

	@Transactional(readOnly = false)
	public void save(Loan loan) {
		loanDao.clear();
		loanDao.save(loan);
	}

	@Transactional(readOnly = false)
	public void delete(Long id) {
		loanDao.deleteById(id);
	}

	/**
	 * 启动流程
	 * 
	 * @param entity
	 */
	public ProcessInstance startWorkflow(Loan entity,
			Map<String, Object> variables) {
		loanDao.save(entity);
		logger.debug("save entity: {}", entity);
		String businessKey = entity.getId().toString();
		// 用来设置启动流程的人员ID，引擎会自动把用户ID保存到activiti:initiator中
		identityService.setAuthenticatedUserId(ObjectUtils.toString(entity
				.getUser().getId()));

		ProcessInstance processInstance = runtimeService
				.startProcessInstanceByKey(ProcessDefinitionKey.loan.getKey(),
						businessKey, variables);

		String processInstanceId = processInstance.getId();
		entity.setProcessInstanceId(processInstanceId);
		loanDao.updateProcessInstanceId(entity.getId(),
				entity.getProcessInstanceId());
		logger.debug(
				"start process of {key={}, bkey={}, pid={}, variables={}}",
				new Object[] { ProcessDefinitionKey.loan.getKey(), businessKey,
						processInstanceId, variables });
		return processInstance;
	}

	/**
	 * 查询待办任务
	 * 
	 * @param userId
	 *            用户ID
	 * @return
	 */
	@Transactional(readOnly = true)
	public List<Loan> findTodoTasks(String userId) {
		List<Loan> results = new ArrayList<Loan>();
		List<Task> tasks = new ArrayList<Task>();

		// 根据当前人的ID查询
		List<Task> todoList = taskService.createTaskQuery()
				.processDefinitionKey(ProcessDefinitionKey.loan.getKey())
				.taskAssignee(userId).active().orderByTaskPriority().desc()
				.orderByTaskCreateTime().desc().list();

		// 根据当前人未签收的任务
		List<Task> unsignedTasks = taskService.createTaskQuery()
				.processDefinitionKey(ProcessDefinitionKey.loan.getKey())
				.taskCandidateUser(userId).active().orderByTaskPriority()
				.desc().orderByTaskCreateTime().desc().list();

		// 合并
		tasks.addAll(todoList);
		tasks.addAll(unsignedTasks);

		// 根据流程的业务ID查询实体并关联
		for (Task task : tasks) {
			String processInstanceId = task.getProcessInstanceId();
			ProcessInstance processInstance = runtimeService
					.createProcessInstanceQuery()
					.processInstanceId(processInstanceId).active()
					.singleResult();
			String businessKey = processInstance.getBusinessKey();
			Loan loan = loanDao.findOne(new Long(businessKey));
			loan.setTask(task);
			loan.setProcessInstance(processInstance);
			loan.setProcessDefinition(getProcessDefinition(processInstance
					.getProcessDefinitionId()));
			results.add(loan);
		}
		return results;
	}

	/**
	 * 读取运行中的流程
	 * 
	 * @return
	 */
	@Transactional(readOnly = true)
	public List<Loan> findRunningProcessInstaces() {
		List<Loan> results = new ArrayList<Loan>();
		List<ProcessInstance> list = runtimeService
				.createProcessInstanceQuery()
				.processDefinitionKey(ProcessDefinitionKey.loan.getKey())
				.active().list();

		// 关联业务实体
		for (ProcessInstance processInstance : list) {
			String businessKey = processInstance.getBusinessKey();
			Loan loan = loanDao.findOne(new Long(businessKey));
			loan.setProcessInstance(processInstance);
			loan.setProcessDefinition(getProcessDefinition(processInstance
					.getProcessDefinitionId()));
			results.add(loan);

			// 设置当前任务信息
			List<Task> tasks = taskService.createTaskQuery()
					.processInstanceId(processInstance.getId()).active()
					.orderByTaskCreateTime().desc().listPage(0, 1);
			loan.setTask(tasks.get(0));

		}
		return results;
	}

	/**
	 * 读取已完成的流程
	 * 
	 * @return
	 */
	@Transactional(readOnly = true)
	public List<Loan> findFinishedProcessInstaces() {
		List<Loan> results = new ArrayList<Loan>();
		List<HistoricProcessInstance> list = historyService
				.createHistoricProcessInstanceQuery()
				.processDefinitionKey(ProcessDefinitionKey.loan.getKey())
				.finished().list();

		// 关联业务实体
		for (HistoricProcessInstance historicProcessInstance : list) {
			String businessKey = historicProcessInstance.getBusinessKey();
			Loan loan = loanDao.findOne(new Long(businessKey));
			loan.setProcessDefinition(getProcessDefinition(historicProcessInstance
					.getProcessDefinitionId()));
			loan.setHistoricProcessInstance(historicProcessInstance);
			results.add(loan);
		}
		return results;
	}

	/**
	 * 查询流程定义对象
	 * 
	 * @param processDefinitionId
	 *            流程定义ID
	 * @return
	 */
	private ProcessDefinition getProcessDefinition(String processDefinitionId) {
		ProcessDefinition processDefinition = repositoryService
				.createProcessDefinitionQuery()
				.processDefinitionId(processDefinitionId).singleResult();
		return processDefinition;
	}
}
